package com.hys.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.json.JSONUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hys.dao.CoopInfoMapper;
import com.hys.entity.CoopInfo;
import com.hys.entity.User;
import com.hys.enums.*;
import com.hys.exception.ServiceException;
import com.hys.param.*;
import com.hys.service.*;
import com.hys.util.BeanUtil;
import com.hys.vo.CooperExcelVO;
import com.hys.vo.CooperInfoVO;
import com.hys.vo.CooperationPageVO;
import com.hys.vo.FileImageVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class CoopInfoServiceImpl extends ServiceImpl<CoopInfoMapper, CoopInfo> implements CoopInfoService {

    @Autowired
    private TaskServiceImpl taskService;

    @Autowired
    private UserService userService;

    @Autowired
    private CoopDetailService coopDetailService;

    @Autowired
    private CoopAuditService coopAuditService;

    @Autowired
    private DictService dictService;

    @Value("${img-up-path}")
    private String imgUpPath;

    @Value("${img-up-url-path}")
    private String imgUpUrlPath;

    @Value("${excel-down-path}")
    private String excelDownPath;


    @Override
    public IPage<CooperationPageVO> page(CooperationPageParam cooperationPage) {

        QueryWrapper<CoopInfo> queryWrapper = new QueryWrapper<>();
        // 当前角色如果为部门人员
        User user = userService.userInfo();
        if(RoleEnum.DEPT_ADMIN.getCode().equals(user.getRole())){
            queryWrapper.lambda().eq(CoopInfo::getCreateUser, user.getId());
        }
        if(cooperationPage.getStatus() != null){
            queryWrapper.lambda().eq(CoopInfo::getStatus, cooperationPage.getStatus());
        }
        if(cooperationPage.getMajor() != null){
            queryWrapper.lambda().like(CoopInfo::getMajor, cooperationPage.getMajor());
        }
        if(cooperationPage.getIsAgreeSigned() != null){
            queryWrapper.lambda().eq(CoopInfo::getIsAgreeSigned, cooperationPage.getIsAgreeSigned());
        }
        queryWrapper.lambda().orderByDesc(CoopInfo::getId);
        IPage<CoopInfo> page = new Page<>(cooperationPage.getPageNum(), cooperationPage.getPageSize());
        page = page(page, queryWrapper);
        // 获取map
        Map<String, String> major = dictService.getByDictTypeRMap("major");
        // 转换结果
        IPage<CooperationPageVO> convertResult = page.convert(coopInfo -> {
            CooperationPageVO coopPageVO = BeanUtil.transform(CooperationPageVO.class, coopInfo);
            coopPageVO.setStatus(CoopStatusEnum.getByCode(coopInfo.getStatus()).getDescription());
            coopPageVO.setIsAgreeSigned(coopInfo.getIsAgreeSigned()?"是":"否");
            coopPageVO.setIsAcceptGraduate(coopInfo.getIsAcceptGraduate()?"是":"否");
            coopPageVO.setIsApprentice(coopInfo.getIsApprentice()?"是":"否");
            coopPageVO.setIsCoBuildBook(coopInfo.getIsCoBuildBook()?"是":"否");
            coopPageVO.setIsCoopEffect(coopInfo.getIsCoopEffect()?"是":"否");
            coopPageVO.setIsDonation(coopInfo.getIsDonation()?"是":"否");
            coopPageVO.setMajor(major.get(coopInfo.getMajor()));
            coopPageVO.setList(taskService.getList(coopPageVO.getId(), coopInfo.getTaskName() ,coopInfo.getBatchNo()));
            // 审核是否可用
            if( CoopStatusEnum.BUILD.getCode().equals(coopInfo.getStatus()) ||
                CoopStatusEnum.REJECTED.getCode().equals(coopInfo.getStatus()) ){
                coopPageVO.setIsEdit(true);
            }else{
                coopPageVO.setIsEdit(false);
            }
            if(CoopStatusEnum.PASSED.getCode().equals(coopInfo.getStatus()) ||
                    CoopStatusEnum.REJECTED.getCode().equals(coopInfo.getStatus())){
                coopPageVO.setIsEnabledAudit(false);
            }else{
                coopPageVO.setIsEnabledAudit( coopAuditService.getIsEnabledAudit(coopInfo));
            }
            return coopPageVO;
        });
        return convertResult;
    }


    @Override
    public void delete(List<Integer> cooperIds) {

        if(CollectionUtil.isEmpty(cooperIds)){
            throw new ServiceException("请选择要删除的记录");
        }
        // 获取当前用户的角色
        Boolean exec = isExec(cooperIds);
        if(exec == false){
            throw new ServiceException("未有权限操作当前记录！");
        }
        List<CoopInfo> coopInfos = listByIds(cooperIds);
        Optional<CoopInfo> any = coopInfos.stream().filter(coopInfo -> CoopStatusEnum.isAbleDelete(coopInfo.getStatus()) == false)
                .findAny();
        if(any.isPresent()){
            throw new ServiceException("状态为审批中或已通过不能进行删除！");
        }
        removeByIds(cooperIds);
    }

    @Override
    @Transactional(rollbackFor = ServiceException.class)
    public void add(CooperAddOrUpdateParam addOrUpdateParam) {

        // 处理参数
        addOrUpdateParam.delWhenBooleanIsFalse();
        // 抽取info的主键值
        CoopInfo coopInfo = addOrUpdateParam.getCoopInfo(userService.userInfo());
        coopInfo.setUpdateUser(userService.userInfo().getId());
        coopInfo.setDeptNo(userService.userInfo().getDeptNo());
        coopInfo.setCreateUser(userService.userInfo().getId());
        coopInfo.setCreateTime(new Date());

        // 保存到详情信息表中
        boolean saveSuccess = save(coopInfo);
        if(saveSuccess == false){
            log.error("资料插入失败:"+ coopInfo.toString());
            throw new ServiceException("资料插入失败！");
        }
        Integer infoId = coopInfo.getId();
        addOrUpdateParam.setId(infoId);
        String detailId = JSONUtil.parse(addOrUpdateParam).toString();
        coopDetailService.add(infoId, detailId);

    }

    @Override
    public CooperInfoVO info(Integer infoId) {

        String detailJson = coopDetailService.getJsonByInfoId(infoId);
        CooperInfoVO cooperInfoVO = JSONUtil.toBean(detailJson, CooperInfoVO.class);
        EnterpriseParam enterpriseParam = cooperInfoVO.getEnterpriseParam();
        enterpriseParam.buildImageUrl(imgUpUrlPath);
        cooperInfoVO.setId(infoId);

        return cooperInfoVO;
    }

    @Override
    public FileImageVO upload(MultipartFile file) {
        // 随机文件名称
        String randomFileName = RandomUtil.randomString(10) + "." + FileUtil.extName(file.getOriginalFilename());
        try {
            file.transferTo( new File(imgUpPath  +"/" + randomFileName));
            // 返回文件名和图片url
        } catch (IOException e) {
            log.error("上传图片失败", e);
            e.printStackTrace();
        }
        FileImageVO fileImageVO = new FileImageVO();
        fileImageVO.setImageName(file.getOriginalFilename());
        fileImageVO.setDiskImageName(randomFileName);
        return fileImageVO;
    }

    @Override
    public void update(CooperAddOrUpdateParam addOrUpdateParam) {

        if(addOrUpdateParam.getId() == null ){
            throw new ServiceException("未查询到要修改的记录");
        }
        CoopInfo record = getById(addOrUpdateParam.getId());
        if(record == null){
            throw new ServiceException("未查询到要修改的记录");
        }
        // 处理参数
        addOrUpdateParam.delWhenBooleanIsFalse();
        User user = userService.userInfo();
        CoopInfo coopInfo = addOrUpdateParam.getCoopInfo(userService.userInfo());
        // 获取数据库中的记录
        if(user.getRole().equals(RoleEnum.DEPT_ADMIN.getCode())){
            if(user.getId().equals(record.getCreateUser()) == false){
                throw new ServiceException("当前用户无权限更改此记录！");
            }
        }
        if(CoopStatusEnum.isAbleUpdate(record.getStatus()) == false){
            throw new ServiceException("当前状态非待审批状态不能编辑！");
        }
        // 更新状态为待审批执行重新审批流程
        coopInfo.setId(addOrUpdateParam.getId());
        coopInfo.setStatus(CoopStatusEnum.BUILD.getCode());
        coopInfo.setBatchNo(null);
        coopInfo.setId(addOrUpdateParam.getId());

        updateById(coopInfo);
        coopDetailService.updateByInfoId(addOrUpdateParam);
    }

    @Override
    public void download(CooperationPageParam cooperationPage, HttpServletResponse response) {

        QueryWrapper<CoopInfo> queryWrapper = new QueryWrapper<>();
        User user = userService.userInfo();
        if(RoleEnum.DEPT_ADMIN.getCode().equals(user.getRole())){
            queryWrapper.lambda().eq(CoopInfo::getCreateUser, user.getId());
        }
        if(cooperationPage.getStatus() != null){
            queryWrapper.lambda().eq(CoopInfo::getStatus, cooperationPage.getStatus());
        }
        if(cooperationPage.getMajor() != null){
            queryWrapper.lambda().eq(CoopInfo::getMajor, cooperationPage.getMajor());
        }
        if(cooperationPage.getIsAgreeSigned() != null){
            queryWrapper.lambda().eq(CoopInfo::getIsAgreeSigned, cooperationPage.getIsAgreeSigned());
        }
        List<CoopInfo> list = list(queryWrapper);

        List<CooperationPageVO> cooperationPageVOList = list.stream().map(coopInfo -> {
            CooperationPageVO coopPageVO = BeanUtil.transform(CooperationPageVO.class, coopInfo);
            coopPageVO.setList(taskService.getList(coopPageVO.getId(), coopInfo.getTaskName(), coopInfo.getBatchNo()));
            coopPageVO.setStatus(CoopStatusEnum.getByCode(coopInfo.getStatus()).getDescription());
            return coopPageVO;
        }).collect(Collectors.toList());

        // 写入到excel文件中
        try {
            toPrintExcel(cooperationPageVOList, response);
        } catch (IOException e) {
            log.error("下载文件失败！", e);
            throw new ServiceException("excel下载失败");
        }
    }

    @Override
    public void toLead(MultipartFile file) throws IOException {
        ExcelReader reader = ExcelUtil.getReader(file.getInputStream());
        List<List<Object>> list = reader.read(4);
        convertToCooperAddOrUpdateParam(list);
    }

    /**
     * @param list
     */
    private void convertToCooperAddOrUpdateParam(List<List<Object>> list) {

        for (int i = 0; i <list.size(); i++) {
            List<Object> beanPropList = list.get(i);
            CooperExcelVO cooperExcelVO = new CooperExcelVO();

            Class<? extends CooperExcelVO> aClass = cooperExcelVO.getClass();
            Field[] declaredFields = aClass.getDeclaredFields();
            for (int x = 0; x < declaredFields.length; x++) {
                Field field = declaredFields[x];
                System.out.println( "---- 打印输出结果 第"+ x +"个:  " + beanPropList.get(x));
                System.out.println( "---- 属性名称 " + field.getName());
                if(beanPropList.get(x) instanceof String){
                    if("否".equals(((String) beanPropList.get(x)).trim())){
                        cn.hutool.core.bean.BeanUtil.setFieldValue(cooperExcelVO, field.getName(), false);
                        continue;
                    }else if("是".equals(((String) beanPropList.get(x)).trim())){
                        cn.hutool.core.bean.BeanUtil.setFieldValue(cooperExcelVO, field.getName(), true);
                        continue;
                    }else{
                        cn.hutool.core.bean.BeanUtil.setFieldValue(cooperExcelVO, field.getName(), beanPropList.get(x));
                        continue;
                    }
                }
                if(beanPropList.get(x) instanceof Double){
                    cn.hutool.core.bean.BeanUtil.setFieldValue(cooperExcelVO, field.getName(), beanPropList.get(x));
                    continue;
                }
                if(beanPropList.get(x) instanceof Long){
                    Long result = (Long) beanPropList.get(x);
                    cn.hutool.core.bean.BeanUtil.setFieldValue(cooperExcelVO, field.getName(), result.intValue());
                    continue;
                }
                throw new ServiceException("出现了未知类型");
            }
            CooperAddOrUpdateParam cooperAddOrUpdate = cooperExcelVO.convertToCooperParam(dictService);
            // 查询当前用户
            String createUser = cooperExcelVO.getCreateUser();
            // 登陆当前填报人
            userService.switchRole(createUser);
            // 添加或更新
            add(cooperAddOrUpdate);
            // 李国良
            StpUtil.login(2);
            coopAuditService.audited(cooperAddOrUpdate.getId(),
                    AuditStatusEnum.PASSED.getCode());
            // 魏红枫
            StpUtil.login(3);
            coopAuditService.audited(cooperAddOrUpdate.getId(),
                    AuditStatusEnum.PASSED.getCode());
            // 陈宇
            StpUtil.login(5);
            coopAuditService.audited(cooperAddOrUpdate.getId(),
                    AuditStatusEnum.PASSED.getCode());
        }
    }

    /**
     * 将vo输出da
     * @param cooperationPageVOList
     */
    private void toPrintExcel(List<CooperationPageVO> cooperationPageVOList, HttpServletResponse response) throws IOException {

        // 获取配置文件
        File file = new File(excelDownPath + "user_statistics_export.xlsx");
        // 使用临时文件修改
        File tempFile = File.createTempFile(RandomUtil.randomString(15), ".xlsx");
        // 将模板文件复制到临时文件
        FileUtil.copy(file, tempFile, true);
        ExcelWriter writer = ExcelUtil.getWriter(tempFile);
        Map<String, String> major = dictService.getByDictTypeRMap("major");

        for (int i = 0; i < cooperationPageVOList.size(); i++) {

            CooperationPageVO coop = cooperationPageVOList.get(i);
            CooperInfoVO info = info(coop.getId());
            CooperExcelVO cooperExcelVO = info.convertToExcelVO();
            // 保存填写资料人和状态
            cooperExcelVO.setStatus(coop.getStatus());
            cooperExcelVO.setCreateUser(userService.getById(coop.getCreateUser()).getName());
            // 企业类型
            cooperExcelVO.setType(EnterTypeEnum.getDescriptionByCode(cooperExcelVO.getType()));
            // 企业性值
            cooperExcelVO.setNature(EnterSizeEnum.getDescriptionByCode(cooperExcelVO.getNature()));
            // 获取派系
            cooperExcelVO.setMajor(major.get(cooperExcelVO.getMajor()));

            Class<? extends CooperExcelVO> aClass = cooperExcelVO.getClass();
            Field[] declaredFields = aClass.getDeclaredFields();
            for (int x = 0; x < declaredFields.length; x++) {
                Field field = declaredFields[x];
                Object fieldValue = cn.hutool.core.bean.BeanUtil.getFieldValue(cooperExcelVO, field.getName());
                if(fieldValue == null){
                    writer.writeCellValue( x,i+3, "无");
                    continue;
                }
                if(fieldValue instanceof Boolean){
                    if((Boolean) fieldValue){
                        writer.writeCellValue( x,i+3, "是");
                    }else{
                        writer.writeCellValue( x,i+3, "否");
                    }
                    continue;
                }
                writer.writeCellValue( x,i+3, fieldValue);
            }
        }
        String fileName = "黑艺术院校校企合作"+ DateUtil.format(new Date(), DatePattern.NORM_DATE_PATTERN)+"信息导出.xlsx";
        response.setHeader("Content-Disposition", "attachment;filename=" + encodeFileName(fileName));
        response.setContentType("application/vnd.ms-excel;charset=utf-8");
        ServletOutputStream outputStream = response.getOutputStream();
        writer.flush(outputStream);
        writer.close();
        outputStream.close();
    }

    private static String encodeFileName(String fileName)  {
        String encodedFileName;
        try{
            encodedFileName = URLEncoder.encode(fileName, "UTF-8");
        }catch ( Exception e ){
            throw new ServiceException("文件名编码异常！");
        }
        // 替换空格为%20，解决部分浏览器中空格被转换为加号的问题
        return encodedFileName.replaceAll("\\+", "%20");
    }

    public Boolean isExec(List<Integer> cooperIds){
        User user = userService.userInfo();
        // 管理员
        if(RoleEnum.ADMIN.getCode().equals(user.getRole())){
            return true;
        }
        // 部门-管理员
        if(RoleEnum.DEPT_ADMIN.getCode().equals(user.getRole())){
            Collection<CoopInfo> coopInfos = listByIds(cooperIds);
            List<String> deptNos = coopInfos.stream().map(CoopInfo::getDeptNo).distinct().collect(Collectors.toList());
            if(deptNos.size() > 1){
                throw new ServiceException("未有权限操作当前记录！");
            }
            String deptNo = deptNos.get(0);
            if( user.getDeptNo().equals(deptNo) == false){
                throw new ServiceException("未有权限操作当前记录！");
            }
            return true;
        }else{
            return false;
        }
    }


}
